package main

import (
	"crypto/rand"
	"flag"
	"fmt"
	"math/big"
	"strings"
)

const (
	lowercaseLetters = "abcdefghijklmnopqrstuvwxyz"
	uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	digits           = "0123456789"
	specialChars     = "!@#$%^&*()-_=+,.?/:;{}[]~"
)

func main() {
	// 定义命令行参数
	length := flag.Int("length", 12, "Length of the password (random if not specified)")
	maxLength := flag.Int("max", 20, "Maximum length of the password")
	useLower := flag.Bool("lower", true, "Use lowercase letters")
	useUpper := flag.Bool("upper", true, "Use uppercase letters")
	useDigits := flag.Bool("digits", true, "Use digits")
	useSpecial := flag.Bool("special", true, "Use special characters")
	flag.Parse()

	// 生成密码
	password, err := generatePassword(*length, *maxLength, *useLower, *useUpper, *useDigits, *useSpecial)
	if err != nil {
		fmt.Println("Error generating password:", err)
		return
	}

	fmt.Println("Generated password:\n", password)   // 输出密码
	fmt.Println("Password length:\n", len(password)) // 输出密码长度
}

func generatePassword(length, maxLength int, useLower, useUpper, useDigits, useSpecial bool) (string, error) {
	// 验证参数
	if maxLength <= 0 {
		return "", fmt.Errorf("max length must be positive")
	}
	if length < 0 {
		return "", fmt.Errorf("length must be non-negative")
	}
	if length > maxLength {
		length = maxLength
	}

	// 如果没有选择任何字符集，使用所有字符集
	if !useLower && !useUpper && !useDigits && !useSpecial {
		useLower, useUpper, useDigits, useSpecial = true, true, true, true
	}

	// 构建字符集
	var charPool string
	if useLower {
		charPool += lowercaseLetters
	}
	if useUpper {
		charPool += uppercaseLetters
	}
	if useDigits {
		charPool += digits
	}
	if useSpecial {
		charPool += specialChars
	}

	if charPool == "" {
		return "", fmt.Errorf("no character sets selected")
	}

	// 如果长度为0，则随机选择长度(8到maxLength之间)
	if length == 0 {
		randomLength, err := rand.Int(rand.Reader, big.NewInt(int64(maxLength-7)))
		if err != nil {
			return "", err
		}
		length = int(randomLength.Int64()) + 8
	}

	// 确保密码长度不超过最大长度
	if length > maxLength {
		length = maxLength
	}

	// 生成密码
	var password strings.Builder
	for i := 0; i < length; i++ {
		charIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(charPool))))
		if err != nil {
			return "", err
		}
		password.WriteByte(charPool[charIndex.Int64()])
	}

	// 确保密码包含至少一个所选字符集中的字符
	// (这里简化处理，实际应用中可能需要更严格的检查)
	return password.String(), nil
}
